import java.awt.Image;
import java.io.BufferedReader;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.net.URL;

import javax.media.opengl.GL;
import javax.media.opengl.glu.GLU;

import com.sun.opengl.util.texture.Texture;
import com.sun.opengl.util.texture.TextureData;
import com.sun.opengl.util.texture.TextureIO;

public class Explosion {
	GL gl;
	GLU glu;
	private int shaderprogram,shaderprogram2,shaderprogram3,shaderprogram4,shaderprogram5, cloud[],meteor[],shockwave[],smoke[],flash[];
	private int vert_shader, frag_shader,vert_shader2, frag_shader2,vert_shader3, frag_shader3,vert_shader4, frag_shader4,vert_shader5, frag_shader5;
	private int puff_num,cur_puff,max_meteor,smoke_num;
	private boolean fire;
	public Vector3D center;
	private Vector3D puff[], speed[],meteors_angle[],meteors[],smoke_puff[],smoke_speed[];
	private float size_puff[],smoke_rot[];
	private float radius,shock_rad;
	Texture boxTexture1,boxTexture2, boxTexture3,boxTexture4,boxTexture5;
	
	public Explosion(GL gl_, GLU glu_){
		gl=gl_;
		glu=glu_;
		cloud = new int[1];
		meteor = new int[1];
		shockwave = new int[1];
		smoke = new int[1];
		flash = new int[1];
		init();
		loadShader();
		loadShader2();
		loadShader3();
		loadShader4();
		loadShader5();
		CreateTexture(null);
	}
	private void init(){
		fire = false;
		cur_puff = 0;
		shock_rad = 1f;
		puff_num = 1000;//number of smoke clouds
		max_meteor = 150;
		smoke_num = 25;
		radius = 0.5f;//sprite radius
		center = new Vector3D(0,0,0);
		puff = new Vector3D[puff_num];
		meteors_angle = new Vector3D[max_meteor];
		meteors = new Vector3D[max_meteor];
		speed = new Vector3D[puff_num];
		smoke_puff = new Vector3D[smoke_num];
		smoke_speed = new Vector3D[smoke_num];
		smoke_rot = new float[smoke_num];
		size_puff = new float[puff_num];
	    for(int i = 0; i < puff_num; i++) {
	        puff[i] = new Vector3D();
	        speed[i] = new Vector3D();
	    }
	    for(int i = 0; i < smoke_num; i++) {
	        smoke_puff[i] = new Vector3D();
	        smoke_speed[i] = new Vector3D();
	    }
	}
	public static float rnd() {
		return (float)Math.random();
	}
	private void smoke_init() {
		for(int i = 0; i < smoke_num; i++) {
	        smoke_rot[i] = (rnd() -0.5f)/20f;
	        smoke_puff[i].setXYZ((rnd() -0.5f)*3f,(rnd() -0.5f)*3f,(rnd() -0.5f)*3f);
	        smoke_speed[i].setXYZ((rnd() -0.5f)*0.1f,(rnd() -0.5f)*0.1f,(rnd() -0.3f)*0.2f);
	    }
	}
	private void clouds_init(){
	    for(int i = 0; i < puff_num; i++) {
	        puff[i].setXYZ(center.x,center.y,center.z);
	        float a = (rnd()-0.5f)*3f,b = (rnd()-0.5f)*3f,c = (rnd()-0.5f)*3f, r = 1f;
	        c = (float) Math.sqrt(Math.pow(r, 2) - Math.pow(a, 2) - Math.pow(b, 2));
	        speed[i].setXYZ(a,b,c);
	        size_puff[i] = rnd()/1.5f + 0.25f; 
	    }
	    for(int i = 0; i < max_meteor; i++) {
	    	meteors_angle[i] = new Vector3D(rnd()*(float)Math.PI*2,rnd()*(float)Math.PI*2,rnd()*(float)Math.PI*2);
	    	meteors[i] = new Vector3D(center.x,center.y,center.z);
	    }
	}
	private void CreateTexture(Image image)
	 {
		 URL imageURL= this.getClass().getResource(
				 "star.png");
	        
		 TextureData data=null;
		 try {
			 data = TextureIO.newTextureData(
					 imageURL.openStream(),false, "png");
			 boxTexture1 = TextureIO.newTexture(data);
		 } catch (IOException exc) {
			 exc.printStackTrace();
			 System.exit(1);
		 }       
	        
		 gl.glEnable(GL.GL_TEXTURE_2D);
		 
		 gl.glGenTextures(1,cloud, 0);
		 gl.glBindTexture(GL.GL_TEXTURE_2D, cloud[0]);
		 gl.glTexImage2D(GL.GL_TEXTURE_2D, 0,GL.GL_RGBA,data.getWidth(),data.getHeight(),0,GL.GL_RGBA,
				 GL.GL_UNSIGNED_BYTE,data.getBuffer());
		 
		 URL imageURL2= this.getClass().getResource(
				 "meteor.png");
	        
		 TextureData data2=null;
		 try {
			 data2 = TextureIO.newTextureData(
					 imageURL2.openStream(),false, "png");
			 boxTexture2 = TextureIO.newTexture(data2);
		 } catch (IOException exc) {
			 exc.printStackTrace();
			 System.exit(1);
		 }       
	        
		 gl.glEnable(GL.GL_TEXTURE_2D);
		 
		 gl.glGenTextures(1,meteor, 0);
		 gl.glBindTexture(GL.GL_TEXTURE_2D, meteor[0]);
		 gl.glTexImage2D(GL.GL_TEXTURE_2D, 0,GL.GL_RGBA,data2.getWidth(),data2.getHeight(),0,GL.GL_RGBA,
				 GL.GL_UNSIGNED_BYTE,data2.getBuffer());
		 URL imageURL3= this.getClass().getResource(
				 "shock.png");
	        
		 TextureData data3=null;
		 try {
			 data3 = TextureIO.newTextureData(
					 imageURL3.openStream(),false, "png");
			 boxTexture3 = TextureIO.newTexture(data3);
		 } catch (IOException exc) {
			 exc.printStackTrace();
			 System.exit(1);
		 }       
	        
		 gl.glEnable(GL.GL_TEXTURE_2D);
		 
		 gl.glGenTextures(1,shockwave, 0);
		 gl.glBindTexture(GL.GL_TEXTURE_2D, shockwave[0]);
		 gl.glTexImage2D(GL.GL_TEXTURE_2D, 0,GL.GL_RGBA,data3.getWidth(),data3.getHeight(),0,GL.GL_RGBA,
				 GL.GL_UNSIGNED_BYTE,data3.getBuffer());
		 URL imageURL4= this.getClass().getResource(
				 "fire.png");
	        
		 TextureData data4=null;
		 try {
			 data4 = TextureIO.newTextureData(
					 imageURL4.openStream(),false, "png");
			 boxTexture4 = TextureIO.newTexture(data4);
		 } catch (IOException exc) {
			 exc.printStackTrace();
			 System.exit(1);
		 }       
	        
		 gl.glEnable(GL.GL_TEXTURE_2D);
		 
		 gl.glGenTextures(1,smoke, 0);
		 gl.glBindTexture(GL.GL_TEXTURE_2D, smoke[0]);
		 gl.glTexImage2D(GL.GL_TEXTURE_2D, 0,GL.GL_RGBA,data4.getWidth(),data4.getHeight(),0,GL.GL_RGBA,
				 GL.GL_UNSIGNED_BYTE,data4.getBuffer());
		 URL imageURL5= this.getClass().getResource(
				 "flash.png");
	        
		 TextureData data5=null;
		 try {
			 data5 = TextureIO.newTextureData(
					 imageURL5.openStream(),false, "png");
			 boxTexture5 = TextureIO.newTexture(data5);
		 } catch (IOException exc) {
			 exc.printStackTrace();
			 System.exit(1);
		 }       
	        
		 gl.glEnable(GL.GL_TEXTURE_2D);
		 
		 gl.glGenTextures(1,flash, 0);
		 gl.glBindTexture(GL.GL_TEXTURE_2D, flash[0]);
		 gl.glTexImage2D(GL.GL_TEXTURE_2D, 0,GL.GL_RGBA,data5.getWidth(),data5.getHeight(),0,GL.GL_RGBA,
				 GL.GL_UNSIGNED_BYTE,data5.getBuffer());
	 }
	
	 private void loadShader(){
		 vert_shader = gl.glCreateShader(GL.GL_VERTEX_SHADER);
	        frag_shader = gl.glCreateShader(GL.GL_FRAGMENT_SHADER);
	        
	        BufferedReader brv = null;
			try {
				brv = new BufferedReader(
						new FileReader(
								"src/exp_round.vert"));
			} catch (FileNotFoundException e1) {
				// TODO Auto-generated catch block
				e1.printStackTrace();
			}
	        String vsrc = "";
	        String line;
	        try {
				while ((line=brv.readLine()) != null) {
				  vsrc += line + "\n";
				}
			} catch (IOException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
	        gl.glShaderSource(vert_shader, 1,
	        		new String[] {vsrc}, (int[])null, 0);
	        gl.glCompileShader(vert_shader);
	        
	        BufferedReader brf = null;
			try {
				brf = new BufferedReader(
						new FileReader(
								"src/exp_round.frag"));
			} catch (FileNotFoundException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
	        String fsrc = "";
	        String lines;
	        try {
				while ((lines=brf.readLine()) != null) {
				  fsrc += lines + "\n";
				}
			} catch (IOException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
	        gl.glShaderSource(frag_shader, 1,
	        		new String[] {fsrc}, (int[])null, 0);
	        gl.glCompileShader(frag_shader);
	        
	        shaderprogram = gl.glCreateProgram();
	        gl.glAttachShader(shaderprogram, vert_shader);
	        gl.glAttachShader(shaderprogram, frag_shader);
	        gl.glLinkProgram(shaderprogram);
	        gl.glValidateProgram(shaderprogram);
	 }
	 private void loadShader2(){
		 vert_shader2 = gl.glCreateShader(GL.GL_VERTEX_SHADER);
	        frag_shader2 = gl.glCreateShader(GL.GL_FRAGMENT_SHADER);
	        
	        BufferedReader brv = null;
			try {
				brv = new BufferedReader(
						new FileReader(
								"src/exp_meteor.vert"));
			} catch (FileNotFoundException e1) {
				// TODO Auto-generated catch block
				e1.printStackTrace();
			}
	        String vsrc = "";
	        String line;
	        try {
				while ((line=brv.readLine()) != null) {
				  vsrc += line + "\n";
				}
			} catch (IOException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
	        gl.glShaderSource(vert_shader2, 1,
	        		new String[] {vsrc}, (int[])null, 0);
	        gl.glCompileShader(vert_shader2);
	        
	        BufferedReader brf = null;
			try {
				brf = new BufferedReader(
						new FileReader(
								"src/exp_meteor.frag"));
			} catch (FileNotFoundException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
	        String fsrc = "";
	        String lines;
	        try {
				while ((lines=brf.readLine()) != null) {
				  fsrc += lines + "\n";
				}
			} catch (IOException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
	        gl.glShaderSource(frag_shader2, 1,
	        		new String[] {fsrc}, (int[])null, 0);
	        gl.glCompileShader(frag_shader2);
	        
	        shaderprogram2 = gl.glCreateProgram();
	        gl.glAttachShader(shaderprogram2, vert_shader2);
	        gl.glAttachShader(shaderprogram2, frag_shader2);
	        gl.glLinkProgram(shaderprogram2);
	        gl.glValidateProgram(shaderprogram2);
	 }
	 private void loadShader3(){
		 vert_shader3 = gl.glCreateShader(GL.GL_VERTEX_SHADER);
	        frag_shader3 = gl.glCreateShader(GL.GL_FRAGMENT_SHADER);
	        
	        BufferedReader brv = null;
			try {
				brv = new BufferedReader(
						new FileReader(
								"src/exp_shock.vert"));
			} catch (FileNotFoundException e1) {
				// TODO Auto-generated catch block
				e1.printStackTrace();
			}
	        String vsrc = "";
	        String line;
	        try {
				while ((line=brv.readLine()) != null) {
				  vsrc += line + "\n";
				}
			} catch (IOException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
	        gl.glShaderSource(vert_shader3, 1,
	        		new String[] {vsrc}, (int[])null, 0);
	        gl.glCompileShader(vert_shader3);
	        
	        BufferedReader brf = null;
			try {
				brf = new BufferedReader(
						new FileReader(
								"src/exp_shock.frag"));
			} catch (FileNotFoundException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
	        String fsrc = "";
	        String lines;
	        try {
				while ((lines=brf.readLine()) != null) {
				  fsrc += lines + "\n";
				}
			} catch (IOException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
	        gl.glShaderSource(frag_shader3, 1,
	        		new String[] {fsrc}, (int[])null, 0);
	        gl.glCompileShader(frag_shader3);
	        
	        shaderprogram3 = gl.glCreateProgram();
	        gl.glAttachShader(shaderprogram3, vert_shader3);
	        gl.glAttachShader(shaderprogram3, frag_shader3);
	        gl.glLinkProgram(shaderprogram3);
	        gl.glValidateProgram(shaderprogram3);
	 }
	 private void loadShader4(){
		 vert_shader4 = gl.glCreateShader(GL.GL_VERTEX_SHADER);
	        frag_shader4 = gl.glCreateShader(GL.GL_FRAGMENT_SHADER);
	        
	        BufferedReader brv = null;
			try {
				brv = new BufferedReader(
						new FileReader(
								"src/exp_fire.vert"));
			} catch (FileNotFoundException e1) {
				// TODO Auto-generated catch block
				e1.printStackTrace();
			}
	        String vsrc = "";
	        String line;
	        try {
				while ((line=brv.readLine()) != null) {
				  vsrc += line + "\n";
				}
			} catch (IOException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
	        gl.glShaderSource(vert_shader4, 1,
	        		new String[] {vsrc}, (int[])null, 0);
	        gl.glCompileShader(vert_shader4);
	        
	        BufferedReader brf = null;
			try {
				brf = new BufferedReader(
						new FileReader(
								"src/exp_fire.frag"));
			} catch (FileNotFoundException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
	        String fsrc = "";
	        String lines;
	        try {
				while ((lines=brf.readLine()) != null) {
				  fsrc += lines + "\n";
				}
			} catch (IOException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
	        gl.glShaderSource(frag_shader4, 1,
	        		new String[] {fsrc}, (int[])null, 0);
	        gl.glCompileShader(frag_shader4);
	        
	        shaderprogram4 = gl.glCreateProgram();
	        gl.glAttachShader(shaderprogram4, vert_shader4);
	        gl.glAttachShader(shaderprogram4, frag_shader4);
	        gl.glLinkProgram(shaderprogram4);
	        gl.glValidateProgram(shaderprogram4);
	 }
	 private void loadShader5(){
		 vert_shader5 = gl.glCreateShader(GL.GL_VERTEX_SHADER);
	        frag_shader5 = gl.glCreateShader(GL.GL_FRAGMENT_SHADER);
	        
	        BufferedReader brv = null;
			try {
				brv = new BufferedReader(
						new FileReader(
								"src/exp_flash.vert"));
			} catch (FileNotFoundException e1) {
				// TODO Auto-generated catch block
				e1.printStackTrace();
			}
	        String vsrc = "";
	        String line;
	        try {
				while ((line=brv.readLine()) != null) {
				  vsrc += line + "\n";
				}
			} catch (IOException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
	        gl.glShaderSource(vert_shader5, 1,
	        		new String[] {vsrc}, (int[])null, 0);
	        gl.glCompileShader(vert_shader5);
	        
	        BufferedReader brf = null;
			try {
				brf = new BufferedReader(
						new FileReader(
								"src/exp_flash.frag"));
			} catch (FileNotFoundException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
	        String fsrc = "";
	        String lines;
	        try {
				while ((lines=brf.readLine()) != null) {
				  fsrc += lines + "\n";
				}
			} catch (IOException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
	        gl.glShaderSource(frag_shader5, 1,
	        		new String[] {fsrc}, (int[])null, 0);
	        gl.glCompileShader(frag_shader5);
	        
	        shaderprogram5 = gl.glCreateProgram();
	        gl.glAttachShader(shaderprogram5, vert_shader5);
	        gl.glAttachShader(shaderprogram5, frag_shader5);
	        gl.glLinkProgram(shaderprogram5);
	        gl.glValidateProgram(shaderprogram5);
	 }
	 private void setShader(){
		 	gl.glActiveTexture(GL.GL_TEXTURE0);
		    gl.glBindTexture(GL.GL_TEXTURE_2D,cloud[0]-1);
	        gl.glUniform1i(gl.glGetUniformLocation(
	        		shaderprogram, "cloud"), 0);
	        gl.glUniform3f(gl.glGetUniformLocation(
	        		shaderprogram, "center"), center.x(), center.y(), center.z());
	 }
	 private void setShader2(){
		 	gl.glActiveTexture(GL.GL_TEXTURE0);
		    gl.glBindTexture(GL.GL_TEXTURE_2D,meteor[0]-1);
	        gl.glUniform1i(gl.glGetUniformLocation(
	        		shaderprogram2, "cloud"), 0);
	        gl.glUniform3f(gl.glGetUniformLocation(
	        		shaderprogram2, "center"), center.x(), center.y(), center.z());
	 }
	 private void setShader3(){
		 	gl.glActiveTexture(GL.GL_TEXTURE0);
		    gl.glBindTexture(GL.GL_TEXTURE_2D,shockwave[0]-1);
	        gl.glUniform1i(gl.glGetUniformLocation(
	        		shaderprogram3, "cloud"), 0);
	        gl.glUniform3f(gl.glGetUniformLocation(
	        		shaderprogram3, "center"), center.x(), center.y(), center.z());
	 }
	 private void setShader4(){
		 	gl.glActiveTexture(GL.GL_TEXTURE0);
		    gl.glBindTexture(GL.GL_TEXTURE_2D,smoke[0]-1);
	        gl.glUniform1i(gl.glGetUniformLocation(
	        		shaderprogram4, "cloud"), 0);
	        gl.glUniform1f(gl.glGetUniformLocation(
	        		shaderprogram4, "time"), shock_rad);
	 }
	 private void setShader5(){
		 	gl.glActiveTexture(GL.GL_TEXTURE0);
		    gl.glBindTexture(GL.GL_TEXTURE_2D,flash[0]-1);
	        gl.glUniform1i(gl.glGetUniformLocation(
	        		shaderprogram5, "cloud"), 0);
	        gl.glUniform1f(gl.glGetUniformLocation(
	        		shaderprogram5, "time"), shock_rad);
	 }
	 public void draw(Camera camera, boolean start, int reflect, Vector3D target) {
		 		center.setXYZ(target);
		 		center.y += 3f;
		 		if(!fire && start && cur_puff == 0) {
		 			cur_puff = 300;
		 			shock_rad = 1;
		 			clouds_init();
		 			smoke_init();
		 			fire = true;
		 		}
		 		else if(reflect == 1) cur_puff -= 3;
		 		if(cur_puff <= 0) {
		 			cur_puff = 0;
		 			fire = false;
		 			return;
		 		}
		 		float yaw = camera.yaw;
		 		float pitch = camera.pitch;
			    Vector3D point1 = new Vector3D(0,-radius,-radius);
			    Vector3D point2 = new Vector3D(0,radius,-radius);
			    Vector3D point3 = new Vector3D(0,radius,radius);
			    Vector3D point4 = new Vector3D(0,-radius,radius);
			    if(reflect == 0) pitch = -pitch;
			    
			    Matrix4x4 matx = new Matrix4x4();
			    Matrix4x4 maty = new Matrix4x4();
			    Matrix4x4 matz = new Matrix4x4();
			    yaw = -yaw;   			    
			    maty = Matrix4x4.set((float)Math.cos(pitch),0,(float)Math.sin(pitch),0,
		                   0,1,0,0,
		                   (float)-Math.sin(pitch),0,(float)Math.cos(pitch),0,
		                   0,0,0,1);
		    

			    matz = Matrix4x4.set((float)Math.cos(yaw+Atmosphere.pi),(float)-Math.sin(yaw+Atmosphere.pi),0,0,
		    		(float)Math.sin(yaw+Atmosphere.pi),(float)Math.cos(yaw+Atmosphere.pi),0,0,
		                   0,0,1,0,
		                   0,0,0,1);
			    
			    point1 = Matrix4x4.mult(Matrix4x4.mult(matz,maty),point1);
			    point2 = Matrix4x4.mult(Matrix4x4.mult(matz,maty),point2);
			    point3 = Matrix4x4.mult(Matrix4x4.mult(matz,maty),point3);
			    point4 = Matrix4x4.mult(Matrix4x4.mult(matz,maty),point4);
			    gl.glUseProgram(shaderprogram);
			    setShader();
			    gl.glEnable(GL.GL_ALPHA_TEST);
			    gl.glEnable(GL.GL_BLEND);
			    gl.glBlendFunc(GL.GL_SRC_ALPHA,GL.GL_ONE_MINUS_SRC_ALPHA);
			    gl.glDepthMask(false);
			    gl.glDisable(GL.GL_CULL_FACE);
			    gl.glBegin(GL.GL_QUADS);
			    for(int i = 0; i< puff_num; i++) {
			    	float size = size_puff[i];
			    	if(reflect == 1) {
			    		Vector3D data = new Vector3D((rnd() - 0.5f)/2f,(rnd() - 0.5f)/2f,(rnd() - 0.5f)/2f);//chaotic dispersion of ashes
			    		speed[i] = Vector3D.add(speed[i], data);
			    		data = Vector3D.div(speed[i], 2f);
			    		puff[i] = Vector3D.add(puff[i], data);
			    		speed[i].setXYZ(speed[i].x/1.03f,speed[i].y/1.03f,speed[i].z/1.03f);//losses of kinetic energy
			    	}
			    	gl.glTexCoord2d(0,0);
			    	gl.glVertex3f(point1.x()*size+puff[i].x(),point1.y()*size+puff[i].y(),point1.z()*size+puff[i].z());

			    	gl.glTexCoord2d(1,0);
			    	gl.glVertex3f(point2.x()*size+puff[i].x(),point2.y()*size+puff[i].y(),point2.z()*size+puff[i].z());

			    	gl.glTexCoord2d(1,1);
			    	gl.glVertex3f(point3.x()*size+puff[i].x(),point3.y()*size+puff[i].y(),point3.z()*size+puff[i].z());

			    	gl.glTexCoord2d(0,1);
			    	gl.glVertex3f(point4.x()*size+puff[i].x(),point4.y()*size+puff[i].y(),point4.z()*size+puff[i].z());
			    }
			    gl.glEnd();
			    gl.glUseProgram(0);
			    gl.glUseProgram(shaderprogram2);
			    setShader2();
			    gl.glBegin(GL.GL_QUADS);
			    for(int i = 0; i< max_meteor; i++) {
			    	point1.setXYZ(0,0,20*radius);
				    point2.setXYZ(0,2*radius,20*radius);
				    point3.setXYZ(0,2*radius,0);
				    point4.setXYZ(0,0,0);
				    float roll = meteors_angle[i].z;
				    yaw = meteors_angle[i].x;
				    pitch = meteors_angle[i].y;
				    Vector3D direction = new Vector3D(0,radius/5f,radius*4f);
				    maty = Matrix4x4.set((float)Math.cos(pitch),0,(float)Math.sin(pitch),0,
			                   0,1,0,0,
			                   (float)-Math.sin(pitch),0,(float)Math.cos(pitch),0,
			                   0,0,0,1);
			    
				    matz = Matrix4x4.set((float)Math.cos(roll),(float)-Math.sin(roll),0,0,
			    		(float)Math.sin(roll),(float)Math.cos(roll),0,0,
			                   0,0,1,0,
			                   0,0,0,1);
				    
				    matx=Matrix4x4.set(1, 0, 0, 0,
				    		0, (float)Math.cos(yaw), (float)-Math.sin(yaw), 0,
				    		0, (float)Math.sin(yaw), (float)Math.cos(yaw),0,
				    		0, 0, 0, 1);
				    
		 	        point1 = Matrix4x4.mult(Matrix4x4.mult(Matrix4x4.mult(matx,maty),matz),point1);
				    point2 = Matrix4x4.mult(Matrix4x4.mult(Matrix4x4.mult(matx,maty),matz),point2);
				    point3 = Matrix4x4.mult(Matrix4x4.mult(Matrix4x4.mult(matx,maty),matz),point3);//rotation
				    point4 = Matrix4x4.mult(Matrix4x4.mult(Matrix4x4.mult(matx,maty),matz),point4);
				    direction = Matrix4x4.mult(Matrix4x4.mult(Matrix4x4.mult(matx,maty),matz),direction);
			    	float size = size_puff[i];
			    	if(reflect == 1) {
			    		meteors[i] = Vector3D.add(meteors[i], Vector3D.div(direction,1.3f/(0.5f*size)));
			    	}
			    	gl.glTexCoord2d(0,0);
			    	gl.glVertex3f(point1.x()*size+meteors[i].x(),point1.y()*size+meteors[i].y(),point1.z()*size+meteors[i].z());

			    	gl.glTexCoord2d(1,0);
			    	gl.glVertex3f(point2.x()*size+meteors[i].x(),point2.y()*size+meteors[i].y(),point2.z()*size+meteors[i].z());

			    	gl.glTexCoord2d(1,1);
			    	gl.glVertex3f(point3.x()*size+meteors[i].x(),point3.y()*size+meteors[i].y(),point3.z()*size+meteors[i].z());

			    	gl.glTexCoord2d(0,1);
			    	gl.glVertex3f(point4.x()*size+meteors[i].x(),point4.y()*size+meteors[i].y(),point4.z()*size+meteors[i].z());
			    }
			    gl.glEnd();
			    gl.glUseProgram(0);
			    gl.glUseProgram(shaderprogram3);
			    setShader3();
			    gl.glBegin(GL.GL_QUADS);
		    	if(reflect == 1) {
		    		shock_rad += 2.0f;
		    	}
		 		yaw = camera.yaw;
		 		pitch = camera.pitch;
		 		yaw = -yaw;
		 		maty = Matrix4x4.set((float)Math.cos(pitch),0,(float)Math.sin(pitch),0,
		                   0,1,0,0,
		                   (float)-Math.sin(pitch),0,(float)Math.cos(pitch),0,
		                   0,0,0,1);
		    

			    matz = Matrix4x4.set((float)Math.cos(yaw+Atmosphere.pi),(float)-Math.sin(yaw+Atmosphere.pi),0,0,
		    		(float)Math.sin(yaw+Atmosphere.pi),(float)Math.cos(yaw+Atmosphere.pi),0,0,
		                   0,0,1,0,
		                   0,0,0,1);
			    point1 = new Vector3D(0,-1,-1);
			    point2 = new Vector3D(0,1,-1);
			    point3 = new Vector3D(0,1,1);
			    point4 = new Vector3D(0,-1,1);
			    point1 = Matrix4x4.mult(Matrix4x4.mult(matz,maty),point1);
			    point2 = Matrix4x4.mult(Matrix4x4.mult(matz,maty),point2);
			    point3 = Matrix4x4.mult(Matrix4x4.mult(matz,maty),point3);
			    point4 = Matrix4x4.mult(Matrix4x4.mult(matz,maty),point4);
		    	gl.glTexCoord2d(0,0);
		    	shock_rad*=2.0f;
		    	gl.glVertex3f(center.x + (-1f)*shock_rad, center.y + (-1f)*shock_rad, center.z + 2.5f);

		    	gl.glTexCoord2d(1,0);
		    	gl.glVertex3f(center.x + (1f)*shock_rad, center.y + (-1f)*shock_rad, center.z + 2.5f);

		    	gl.glTexCoord2d(1,1);
		    	gl.glVertex3f(center.x + (1f)*shock_rad, center.y + (1f)*shock_rad, center.z + 2.5f);

		    	gl.glTexCoord2d(0,1);
		    	gl.glVertex3f(center.x + (-1f)*shock_rad, center.y + (1f)*shock_rad, center.z + 2.5f);
		    	//
		    	gl.glTexCoord2d(0,0);
		    	gl.glVertex3f(center.x + point1.x*shock_rad, center.y + point1.y*shock_rad, center.z + point1.z*shock_rad);

		    	gl.glTexCoord2d(1,0);
		    	gl.glVertex3f(center.x + point2.x*shock_rad, center.y + point2.y*shock_rad, center.z + point2.z*shock_rad);

		    	gl.glTexCoord2d(1,1);
		    	gl.glVertex3f(center.x + point3.x*shock_rad, center.y + point3.y*shock_rad, center.z + point3.z*shock_rad);

		    	gl.glTexCoord2d(0,1);
		    	gl.glVertex3f(center.x + point4.x*shock_rad, center.y + point4.y*shock_rad, center.z + point4.z*shock_rad);
		    	shock_rad/=2.0f;
			    gl.glEnd();
			    gl.glUseProgram(0);
			    gl.glUseProgram(shaderprogram4);
			    setShader4();
			    gl.glBegin(GL.GL_QUADS);
			    for(int i = 0; i< smoke_num; i++) {
				    radius = 8.0f*20f*smoke_rot[i]+shock_rad/16.0f;
				    point1.setXYZ(0,-radius,-radius);
				    point2.setXYZ(0,radius,-radius);
				    point3.setXYZ(0,radius,radius);
				    point4.setXYZ(0,-radius,radius);
			    	smoke_puff[i] = Vector3D.add(smoke_puff[i],smoke_speed[i]);
				    pitch = camera.pitch;
				    yaw = camera.yaw;
			    	if(reflect == 0) pitch = -pitch;
				    yaw = -yaw; 
				    maty = Matrix4x4.set((float)Math.cos(pitch),0,(float)Math.sin(pitch),0,
			                   0,1,0,0,
			                   (float)-Math.sin(pitch),0,(float)Math.cos(pitch),0,
			                   0,0,0,1);
			    


				    matz = Matrix4x4.set((float)Math.cos(yaw+Atmosphere.pi),(float)-Math.sin(yaw+Atmosphere.pi),0,0,
			    		(float)Math.sin(yaw+Atmosphere.pi),(float)Math.cos(yaw+Atmosphere.pi),0,0,
			                   0,0,1,0,
			                   0,0,0,1);
				    yaw = smoke_rot[i]*shock_rad;
				    matx = Matrix4x4.set(1, 0, 0, 0,
			 	    		0, (float)Math.cos(yaw), (float)-Math.sin(yaw), 0,
			 	    		0, (float)Math.sin(yaw), (float)Math.cos(yaw),0,
			 	    		0, 0, 0, 1);
				    point1 = Matrix4x4.mult(Matrix4x4.mult(Matrix4x4.mult(matz,maty),matx),point1);
				    point2 = Matrix4x4.mult(Matrix4x4.mult(Matrix4x4.mult(matz,maty),matx),point2);
				    point3 = Matrix4x4.mult(Matrix4x4.mult(Matrix4x4.mult(matz,maty),matx),point3);
				    point4 = Matrix4x4.mult(Matrix4x4.mult(Matrix4x4.mult(matz,maty),matx),point4);
			    	gl.glTexCoord2d(0,0);
			    	gl.glVertex3f(point1.x()+ center.x() + smoke_puff[i].x(),point1.y()+ center.y() + smoke_puff[i].y(),point1.z()+ center.z() + smoke_puff[i].z());

			    	gl.glTexCoord2d(1,0);
			    	gl.glVertex3f(point2.x()+ center.x() + smoke_puff[i].x(),point2.y()+ center.y() + smoke_puff[i].y(),point2.z()+ center.z() + smoke_puff[i].z());

			    	gl.glTexCoord2d(1,1);
			    	gl.glVertex3f(point3.x()+ center.x() + smoke_puff[i].x(),point3.y()+ center.y() + smoke_puff[i].y(),point3.z()+ center.z() + smoke_puff[i].z());

			    	gl.glTexCoord2d(0,1);
			    	gl.glVertex3f(point4.x()+ center.x() + smoke_puff[i].x(),point4.y()+ center.y() + smoke_puff[i].y(),point4.z()+ center.z() + smoke_puff[i].z());
			    }
			    gl.glEnd();
			    radius = shock_rad/3.0f;
			    gl.glUseProgram(0);
			    gl.glUseProgram(shaderprogram5);
			    setShader5();
			    yaw = camera.yaw;
			    pitch = camera.pitch;
			    point1 = new Vector3D(0,-radius,-radius);
			    point2 = new Vector3D(0,radius,-radius);
			    point3 = new Vector3D(0,radius,radius);
			    point4 = new Vector3D(0,-radius,radius);
			    if(reflect == 0) pitch = -pitch;

			    yaw = -yaw;   			    
			    maty = Matrix4x4.set((float)Math.cos(pitch),0,(float)Math.sin(pitch),0,
		                   0,1,0,0,
		                   (float)-Math.sin(pitch),0,(float)Math.cos(pitch),0,
		                   0,0,0,1);
		    

			    matz = Matrix4x4.set((float)Math.cos(yaw+Atmosphere.pi),(float)-Math.sin(yaw+Atmosphere.pi),0,0,
		    		(float)Math.sin(yaw+Atmosphere.pi),(float)Math.cos(yaw+Atmosphere.pi),0,0,
		                   0,0,1,0,
		                   0,0,0,1);
			    
			    point1 = Matrix4x4.mult(Matrix4x4.mult(matz,maty),point1);
			    point2 = Matrix4x4.mult(Matrix4x4.mult(matz,maty),point2);
			    point3 = Matrix4x4.mult(Matrix4x4.mult(matz,maty),point3);
			    point4 = Matrix4x4.mult(Matrix4x4.mult(matz,maty),point4);
			    gl.glBegin(GL.GL_QUADS);
   
		    	gl.glTexCoord2d(0,0);
		    	gl.glVertex3f(point1.x()+center.x(),point1.y()+center.y(),point1.z()+1.5f+center.z());
		    	gl.glTexCoord2d(1,0);
		    	gl.glVertex3f(point2.x()+center.x(),point2.y()+center.y(),point2.z()+1.5f+center.z());
		    	gl.glTexCoord2d(1,1);
		    	gl.glVertex3f(point3.x()+center.x(),point3.y()+center.y(),point3.z()+1.5f+center.z());
			    gl.glTexCoord2d(0,1);
			    gl.glVertex3f(point4.x()+center.x(),point4.y()+center.y(),point4.z()+1.5f+center.z());
			    radius = 0.5f;
			    gl.glEnd();
			    gl.glDepthMask(true);
			    gl.glEnable(GL.GL_CULL_FACE);
			    gl.glDisable(GL.GL_ALPHA_TEST);
			    gl.glDisable(GL.GL_BLEND);
			    gl.glUseProgram(0);
	}
}